package com.lqjava.flowable.serverapp.app.service.common;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lqjava.flowable.beans.entity.request.IDRequest;
import com.lqjava.flowable.beans.exceptions.ServiceException;
import com.lqjava.flowable.beans.mapper.common.ICRUDMapper;
import com.lqjava.flowable.beans.utils.MyBatisSQLInfo;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class ABSCRUDServiceImpl<T> implements ICRUDService<T> {

	@Override
	public abstract ICRUDMapper<T> getBaseMapper();

	@Override
	public T get(IDRequest request){
		if(request == null) return  null;
		return this.get(request.getId());
	}

	@Override
	public T get(Long id) {
		if(id == null) return null;
		return getBaseMapper().selectById(id);
	}

	@Override
	public List<T> selectByIdList(List<Long> idList) {
		if(idList == null || idList.size() == 0) return new ArrayList<>();
		QueryWrapper<T> objectQueryWrapper = new QueryWrapper<>();
		objectQueryWrapper.in(this.getIdFiledName(),idList);
		return getBaseMapper().selectList(objectQueryWrapper);
	}

	@Override
	public Long insert(T entity) {
		if(getBaseMapper().insert(entity) == 0) ServiceException.throwBusiness("插入失败");
		return JSON.parseObject(JSON.toJSONString(entity)).getLong("id");
	}

	@Override
	public Long update(T entity) {
		Long id = JSON.parseObject(JSON.toJSONString(entity)).getLong("id");
		if(id == null) ServiceException.throwBusiness("id不能为空");
		if(getBaseMapper().updateById(entity) == 0) ServiceException.throwBusiness("修改失败");
		return id;
	}

	@Override
	public Long del(IDRequest request) {
		if(request == null) ServiceException.throwBusiness("id不能为空");
		if(request.getId() == null) ServiceException.throwBusiness("id不能为空");
		if(getBaseMapper().deleteById(request.getId()) == 0) ServiceException.throwBusiness("删除失败");
		return request.getId();
	}


	@Override
	public Integer batchInsert(List<T> entityList) {
		if(entityList == null || entityList.size() == 0) return 0;
		MyBatisSQLInfo<T> sqlInfo = new MyBatisSQLInfo(entityList.get(0).getClass());
		String tableName = sqlInfo.getTableName();
		String cols = String.format(" ( %s ) ",sqlInfo.getInsertCols());
		StringBuffer values = new StringBuffer();
		entityList.forEach(entity -> {
			values.append(String.format("(%s),",sqlInfo.getInsertValues(entity)));
		});
		values.deleteCharAt(values.length() - 1);
		return this.getBaseMapper().execSql2Insert(tableName, cols, values.toString());
	}

	@Override
	public Integer batchUpdate(T entity, Wrapper<T> wrapper) {
		return this.getBaseMapper().update(entity, wrapper);
	}

	@Override
	public boolean save(T entity) {
		return this.insert(entity) != null;
	}

	@Override
	public boolean saveBatch(Collection<T> entityList, int batchSize) {
		this.batchInsert(entityList.stream().collect(Collectors.toList()));
		return  true;

	}

	@Override
	public boolean saveOrUpdate(T entity) {
		boolean isInsert = JSON.parseObject(JSON.toJSONString(entity)).get("id") != null;
		return (isInsert ? this.insert(entity) : this.update(entity)) != null;
	}

	@Override
	@Transactional
	public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
		List<T> insertList = new ArrayList<>();
		List<T> updateList = new ArrayList<>();
		for (T entity : entityList) {
			if(getId(entity) != null){
				insertList.add(entity);
			}else{
				updateList.add(entity);
			}
		}
		this.batchInsert(insertList);
		updateList.forEach(this::update);
		return true;
	}

	@Override
	public boolean updateBatchById(Collection<T> entityList, int batchSize) {
		entityList.forEach(this::update);
		return true;
	}
	@Override
	public Map<String, Object> getMap(Wrapper<T> queryWrapper) {
		return null;
	}

	@Override
	public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
		return null;
	}

	@Override
	public T getOne(Wrapper<T> queryWrapper, boolean throwEx) {
		return null;
	}

	//后期可优化
	protected Long getId(T entity){
		Object idValue = JSON.parseObject(JSON.toJSONString(entity)).get(this.getIdFiledName());
		return idValue != null ? Long.valueOf(idValue.toString()) : null;
	}
	//后期可优化 T的类型获取
	protected String getIdFiledName(){
		return "id";
	}
}
